package com.base.commons.tools.exception;

import com.base.commons.tools.enums.SystemEnum;
import com.base.commons.tools.utils.Result;
import com.base.commons.tools.utils.StringUtils;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 异常处理器
 *
 * @author carl
 * @since 1.0.0
 */
@RestControllerAdvice
@Slf4j
public class BaseOfExceptionHandler {

	@Value("${log.level:DEBUG}")
	private String logLevel;

	/**
	 * 插入数据自定义异常
	 * */
	@ExceptionHandler(DuplicateKeyException.class)
	public Result handleDuplicateKeyException(DuplicateKeyException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(ErrorCode.DB_RECORD_EXISTS,debugEnable,ex);
	}


	@ExceptionHandler(Exception.class)
	public Result handleException(Exception ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(debugEnable,ex);
	}

	@ExceptionHandler(HttpMessageNotReadableException.class)
	public Result httpMessageNotReadableException(HttpMessageNotReadableException ex){
		Throwable throwable = ex.getCause().getCause();
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		if(throwable != null && throwable instanceof BaseOfException){
			BaseOfException ztenException = (BaseOfException)throwable;
			return Result.error(ztenException.getCode(),ztenException.getMessage(),debugEnable,ex);
		}

		return Result.error(400,"Parameters of the abnormal",debugEnable,ex);
	}

	@ExceptionHandler(ParamException.class)
	public Result paramException(ParamException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(HttpStatus.BAD_REQUEST.value(),ex.getMessage(),debugEnable,ex);
	}

	@ExceptionHandler(MismatchedInputException.class)
	public Result httpMismatchedInputException(MismatchedInputException ex){
		Throwable throwable = ex.getCause().getCause();
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		if(throwable != null && throwable instanceof BaseOfException){
			BaseOfException exception = (BaseOfException)throwable;
			return Result.error(exception.getCode(),exception.getMessage(),debugEnable,ex);
		}
		return Result.error(debugEnable,ex);
	}
	/**
	 * 处理自定义异常
	 */
	@ExceptionHandler(BaseOfException.class)
	public Result handleZtenException(BaseOfException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(ex.getCode(), ex.getMessage(),debugEnable,ex);
	}

	/**
	 * 处理WMS异常
	 */
	@ExceptionHandler(WmsException.class)
	public Result handleWmsException(WmsException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(ex.getCode(), ex.getMessage(),debugEnable,ex, SystemEnum.WMS);
	}

	/**
	 * 处理FMS异常
	 */
	@ExceptionHandler(FmsException.class)
	public Result handleFmsException(FmsException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(ex.getCode(), ex.getMessage(),debugEnable,ex, SystemEnum.FMS);
	}

	/**
	 * 处理BSC异常
	 */
	@ExceptionHandler(BscException.class)
	public Result handleBscException(BscException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(ex.getCode(), ex.getMessage(),debugEnable,ex, SystemEnum.BSC);
	}

	/**
	 * 处理BMS异常
	 */
	@ExceptionHandler(BmsException.class)
	public Result handleBmsException(BmsException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(ex.getCode(), ex.getMessage(),debugEnable,ex, SystemEnum.BMS);
	}

	/**
	 * 处理BMS异常
	 */
	@ExceptionHandler(PscException.class)
	public Result handlePscException(PscException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(ex.getCode(), ex.getMessage(),debugEnable,ex, SystemEnum.PSC);
	}

	/**
	 * 处理OWMS异常
	 */
	@ExceptionHandler(OwmsException.class)
	public Result handleOwmsException(OwmsException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(ex.getCode(), ex.getMessage(),debugEnable,ex, SystemEnum.OWMS);
	}

	/**
	 * 处理TMS异常
	 */
	@ExceptionHandler(TmsException.class)
	public Result handleTmsException(TmsException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(ex.getCode(), ex.getMessage(),debugEnable,ex, SystemEnum.TMS);
	}

	/**
	 * 处理MDC异常
	 */
	@ExceptionHandler(MdcException.class)
	public Result handleMdcException(MdcException ex){
		log.error(request(ex),ex);
		boolean debugEnable = getDebugEnable(logLevel);
		return Result.error(ex.getCode(), ex.getMessage(),debugEnable,ex, SystemEnum.MDC);
	}

	/**
	 * 是否开启debug响应
	 * @param logLevel
	 * @return
	 */
	public boolean getDebugEnable(String logLevel){
		return "DEBUG".equalsIgnoreCase(logLevel);
	}


	/** 输出整个请求上下文 */
	private String request(Exception e) {
		String requestInfo = MDC.get("requestInfo");
		if (StringUtils.isEmpty(requestInfo)) {
			return e.getMessage();
		}

		String requestTime = MDC.get("requestTime");
		if (StringUtils.isNotEmpty(requestTime)) {
			try {
				long time = System.currentTimeMillis() - Long.parseLong(requestTime);
				if (time > 0) {
					return "耗时: (" + time + "ms), " + requestInfo;
				}
			} catch (NumberFormatException ignore) {
			}
		}
		return requestInfo;
	}
}
